/***************************************************************************
 *   Copyright (C) %{CURRENT_YEAR} by Lindsay Mathieson <lindsay.mathieson@kdemail.net>                            *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA .        *
 ***************************************************************************/

#include "kwhirlmon.h"
#include "kwhirlmonview.h"
#include "settings.h"

#include <QtGui/QDropEvent>
#include <QtGui/QPainter>
#include <QtGui/QPrinter>

#include <KConfigDialog>
#include <KStatusBar>

#include <KAction>
#include <KActionCollection>
#include <KStandardAction>

#include <KLocale>
#include <KMessageBox>
#include <QMenu>
#include <KApplication>
#include <KMenu>
#include <KColorScheme>
#include <QDesktopServices>
#include <KNotification>


KWhirlMon::KWhirlMon()
    : KXmlGuiWindow(), m_RefreshTimer(this),
      m_view(new KWhirlMonView(this))
{
    m_Notifier = new KStatusNotifierItem(this);
    m_Notifier->setIconByName("kwhirlmon");
    m_Notifier->setToolTip("kwhirlmon", "KWhirlMon", "");
    m_Notifier->setCategory(KStatusNotifierItem::Communications);
    m_Notifier->setStatus(KStatusNotifierItem::NeedsAttention);


    // accept dnd
    setAcceptDrops(true);

    // tell the KXmlGuiWindow that this is indeed the main widget
    setCentralWidget(m_view);

    // then, setup our actions
    setupActions();

    // add a status bar
    statusBar()->show();

    // a call to KXmlGuiWindow::setupGUI() populates the GUI
    // with actions, using KXMLGUI.
    // It also applies the saved mainwindow settings, if any, and ask the
    // mainwindow to automatically save settings if changed: window size,
    // toolbar position, icon size, etc.
    setupGUI();

    emit settingsChanged();
}

KWhirlMon::~KWhirlMon()
{
}

void KWhirlMon::setupActions()
{
    aRefresh = new KAction(KIcon("view-refresh"), i18n("Refresh"), this);
	aMarkRead = new KAction(KIcon("mail-mark-read"), i18n("Mark Read"), this);
	aMarkAllRead = new KAction(KIcon("mail-mark-important"), i18n("Mark All Read"), this);

    actionCollection()->addAction(QLatin1String("refresh_action"), aRefresh);
	actionCollection()->addAction(QLatin1String("mark_read_action"), aMarkRead);
	actionCollection()->addAction(QLatin1String("mark_all_read_action"), aMarkAllRead);

    m_Notifier->contextMenu()->addAction(aRefresh);

    connect(aRefresh, SIGNAL(triggered(bool)), this, SLOT(refresh()));
	connect(aMarkRead, SIGNAL(triggered(bool)), this, SLOT(markRead()));
	connect(aMarkAllRead, SIGNAL(triggered(bool)), this, SLOT(markAllRead()));
    connect(&m_RefreshTimer, SIGNAL(timeout()), this, SLOT(tmRefresh()));
    connect(m_view, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(customContextMenuRequested(QPoint)));
    connect(m_view, SIGNAL(activated(QModelIndex)), this, SLOT(threadActivated(QModelIndex)));
	connect(m_view->selectionModel(), SIGNAL(selectionChanged(QItemSelection,QItemSelection)), this, SLOT(selectionChanged(QItemSelection,QItemSelection)));


    KStandardAction::quit(this, SLOT(onQuit()), actionCollection());
    KStandardAction::preferences(this, SLOT(optionsPreferences()), actionCollection());

	// enable/disable
	aMarkRead->setEnabled(false);
	aMarkAllRead->setEnabled(false);
}


void KWhirlMon::optionsPreferences()
{
    // The preference dialog is derived from prefs_base.ui
    //
    // compare the names of the widgets in the .ui file
    // to the names of the variables in the .kcfg file
    //avoid to have 2 dialogs shown
    if ( KConfigDialog::showDialog( "settings" ) )  {
        return;
    }
    KConfigDialog *dialog = new KConfigDialog(this, "settings", Settings::self());
    QWidget *generalSettingsDlg = new QWidget;
    ui_prefs_base.setupUi(generalSettingsDlg);
    dialog->addPage(generalSettingsDlg, i18n("General"), "kwhirlmon");
    connect(dialog, SIGNAL(settingsChanged(QString)), this, SLOT(settingsChanged()));
    dialog->setAttribute( Qt::WA_DeleteOnClose );
    dialog->show();

}

static bool isQuitting = false;

void KWhirlMon::onQuit()
{
    isQuitting = true;
    close();
}

void KWhirlMon::closeEvent(QCloseEvent *event)
{
    if (! isQuitting) {
        /*
         *		KMessageBox::information(this, tr("Systray"),
         *										tr("The program will keep running in the "
         *										"system tray. To terminate the program, "
         *										"choose <b>Quit</b> in the context menu "
         *										"of the system tray entry."));
         */
        hide();
        event->ignore();
    }
}

void KWhirlMon::threadActivated(QModelIndex cell)
{
    kDebug() << "threadActivated(" << cell.column() << "," << cell.row() << ")" << endl;

    const WatchedThreadData &th = m_view->threadModel.threads[cell.row()];

    // Open in default browser
    QDesktopServices::openUrl(th.getOpenUrl());

	MarkThreadRead(cell.row(), Settings::hide_when_finished());
}

void KWhirlMon::MarkThreadRead(int row, bool autoHide)
{
    const WatchedThreadData &th = m_view->threadModel.threads[row];

	if (th.unread == 0)
        return;

    // Visually indicate we're marking this read.
    m_view->threadModel.setPendingMarkRead(row, true);

    // Issue Mark Read Call
    QNetworkReply *reply = manager.get(QNetworkRequest(th.getMarkReadUrl(autoHide)));
	connect(reply, SIGNAL(finished()), this, SLOT(markReadFinished()));
}

void KWhirlMon::settingsChanged()
{
    /*
     * 0 = None
     * 1 = 5
     * 2 = 10
     * 3 = 15
     * 4 = 30
     */

    int min = 5;
    switch(Settings::poll_period())
    {
    case 0:
        min = 0;
        break;
    case 1:
        min = 5;
        break;
    case 2:
        min = 10;
        break;
    case 3:
        min = 15;
        break;
    case 4:
        min = 30;
        break;
    }
    kDebug() << "Poll Period = " << min << " minutes";
    if (min == 0)
        m_RefreshTimer.stop();
    else
        m_RefreshTimer.start(1000 * 60 * min);
    emit refresh();
}


void KWhirlMon::refresh()
{
    kDebug() << "REFRESH";

    if (KWhirlMon::aRefresh)
        KWhirlMon::aRefresh->setIcon(KIcon("stop"));

    QNetworkReply *reply = manager.get(QNetworkRequest(WatchedThreadData::getWatchedUrl(Settings::unread_only())));
    connect(reply, SIGNAL(finished()), this, SLOT(refreshFinished()));
}

void KWhirlMon::refreshFinished()
{
    kDebug() << "refreshFinished" << endl;
    QNetworkReply *reply = qobject_cast<QNetworkReply *>(sender());
    if (reply->error() != QNetworkReply::NoError)
    {
        kDebug() << reply->errorString() << endl;
        return;
    }

    QByteArray data = reply->readAll();

    WatchedThreadData::List threads2 = WatchedThreadData::parseJson(data);
    if (Settings::notify_new_msgs())
    {
        if (WatchedThreadData::NewMessagesInW2(m_view->threadModel.threads, threads2))
        {
            WatchedThreadData::Summary summary = threads2.getSummary();

            // Notify user
            QString text = summary.getText();

            KNotification *notification= new KNotification ("newmsgs", KNotification::CloseWhenWidgetActivated, this);
            notification->setTitle(i18n("KWhirlMon"));
            notification->setText(text);
            notification->setActions(QStringList(i18n("Open")));
            connect(notification, SIGNAL(activated(unsigned int )), this , SLOT(notify()));
            notification->sendEvent();
        }
    }

    m_view->threadModel.setThread(threads2);

    if (aRefresh)
        aRefresh->setIcon(KIcon("view-refresh"));

    reply->deleteLater();

    updateCount();
}

void KWhirlMon::notify()
{
    kDebug() << "*** NOTIFY ***";
    m_Notifier->activate();
}
void KWhirlMon::markReadFinished()
{
    kDebug() << "markReadFinished" << endl;
    QNetworkReply *reply = qobject_cast<QNetworkReply *>(sender());
    if (reply->error() != QNetworkReply::NoError)
    {
        kDebug() << reply->errorString() << endl;
        return;
    }

	bool autoHide = reply->url().hasEncodedQueryItem("autohide");
    QString sid(reply->url().encodedQueryItemValue("watchedread"));
    bool ok;
    long id = sid.toLong(&ok, 10);
    if (ok)
    {
        kDebug() << "Thread Id = " << id;
        WatchedThreadModel& threadModel = m_view->threadModel;
        for (int r = 0; r < threadModel.threads.count(); r++)
        {
            WatchedThreadData &th = threadModel.threads[r];
            if (th.id == id)
            {
                if (Settings::unread_only())
                    threadModel.removeRow(r);
                else
                {
                    th.unread = 0;
                    threadModel.setPendingMarkRead(r, false);
                }
                break;
            };
        };
    }
    else
        kDebug() << "Failed to decode id";

    reply->deleteLater();
    updateCount();

	// Hide to tray?
	if (autoHide)
	{
		WatchedThreadData::Summary summary = m_view->threadModel.threads.getSummary();
		if (summary.nUnreadMsgs == 0)
			hide();
	};	
}



void KWhirlMon::updateCount()
{
    WatchedThreadData::Summary summary = m_view->threadModel.threads.getSummary();
    m_Notifier->setIconByName( "kwhirlmon");
    m_Notifier->setToolTipSubTitle(summary.getText());
	aMarkAllRead->setEnabled(summary.nUnreadMsgs > 0);
	
    if(summary.nUnreadMsgs == 0)
        return;


    const int overlaySize = KIconLoader::SizeSmallMedium;

    const QString countString = QString::number( summary.nUnreadMsgs );
    QFont countFont = KGlobalSettings::generalFont();
    countFont.setBold(true);

    // decrease the size of the font for the number of unread messages if the
    // number doesn't fit into the available space
    float countFontSize = countFont.pointSizeF();
    QFontMetrics qfm( countFont );
    int width = qfm.width( countString );
    if( width > (overlaySize - 2) )
    {
        countFontSize *= float( overlaySize - 2 ) / float( width );
        countFont.setPointSizeF( countFontSize );
    }

    // Paint the number in a pixmap
    QPixmap overlayPixmap( overlaySize, overlaySize );
    overlayPixmap.fill( Qt::transparent );

    QPainter p( &overlayPixmap );
    p.setFont( countFont );
    KColorScheme scheme( QPalette::Active, KColorScheme::View );

    p.setBrush( Qt::NoBrush );
    //p.setPen( scheme.foreground( KColorScheme::LinkText).color() );
    p.setPen( Qt::white);
    p.setOpacity( 1.0 );
    p.drawText( overlayPixmap.rect(), Qt::AlignCenter, countString );
    p.end();

    KIcon mIcon("kwhirlmon");
    QPixmap iconPixmap = mIcon.pixmap(overlaySize, overlaySize);

    QPainter pp(&iconPixmap);
    pp.drawPixmap(0, 0, overlayPixmap);
    pp.end();

    m_Notifier->setIconByPixmap( iconPixmap );
    m_Notifier->setStatus(KStatusNotifierItem::Active);
}

void KWhirlMon::tmRefresh()
{
    emit refresh();
}

void KWhirlMon::markRead()
{
	QModelIndex idx = m_view->selectionModel()->currentIndex();
	// sanity check
	if (! idx.isValid())
		return;

	MarkThreadRead(idx.row(), false);
}

void KWhirlMon::markAllRead()
{
	for (int row = 0; row < m_view->model()->rowCount(); row++)
		MarkThreadRead(row, false);
}

void KWhirlMon::customContextMenuRequested(const QPoint & pos)
{
	QPoint globalPos = m_view->mapToGlobal(pos);
	
	KMenu contextMenu;
	contextMenu.addAction(aMarkRead);
	contextMenu.addAction(aMarkAllRead);
	contextMenu.addAction(aRefresh);

	contextMenu.exec(globalPos);
}

void KWhirlMon::selectionChanged (const QItemSelection & selected, const QItemSelection & deselected)
{
	Q_UNUSED(deselected);
	aMarkRead->setEnabled(! selected.empty());
}

#include "kwhirlmon.moc"
